package com.cmw.http.server;

import com.cmw.constant.UDPConstants;
import com.cmw.util.ByteUtils;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.ByteBuffer;
import java.util.UUID;

public class ServerProvider {
    private static  Provider PROVIDER_INSTANCE;

    static void start(int port){
        stop();
        String sn = UUID.randomUUID().toString();
        Provider provider = new Provider(sn, port);
        provider.start();
        PROVIDER_INSTANCE = provider;
    }

    static void stop(){
        if(null == PROVIDER_INSTANCE) return;
        PROVIDER_INSTANCE.exit();
        PROVIDER_INSTANCE = null;
    }

    private static class Provider extends Thread{
        private final byte[] sn;

        private final int port;

        private boolean done = false;

        private DatagramSocket ds = null;
        //存储消息的Buffer
        final byte[] buffer = new byte[128];

        private Provider(String sn, int port) {
            this.sn = sn.getBytes();
            this.port = port;
        }

        @Override
        public void run() {
            super.run();
            System.out.println("UDPProvier Started.");
            try{
                //监听 服务器UDP端口
                ds = new DatagramSocket(UDPConstants.PORT_SERVER);
                //接收消息的 Packet
                DatagramPacket receivePack = new DatagramPacket(buffer, buffer.length);

                while (!done){
                    //接收数据包
                    ds.receive(receivePack);
                    String clientIp = receivePack.getAddress().getHostAddress();
                    int clientPort = receivePack.getPort();
                    int clientDataLen = receivePack.getLength();
                    byte[] clientData = receivePack.getData();
                    boolean isValid = clientDataLen >= (UDPConstants.HEADER.length + 2 + 4)
                            && ByteUtils.startsWith(clientData, UDPConstants.HEADER);
                    System.out.println(String.format("ServerProvider receive form ip:%s\tport:%d\tdataValid:%s",clientIp, clientPort, isValid+""));
                    if(!isValid){
                        continue;
                    }

                    //解析命令与回送端口
                    int index = UDPConstants.HEADER.length;
                    short cmd = (short)((clientData[index++] << 8) | (clientData[index++] & 0xff));
                    int responsePort = (((clientData[index++]) << 24) |
                            ((clientData[index++] & 0xff) << 16) |
                            ((clientData[index++] & 0xff) << 8) |
                            ((clientData[index] & 0xff)));
                    // 判断合法性
                    if(cmd == 1 && responsePort > 0){
                        //构建一份回送数据
                        ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
                        byteBuffer.put(UDPConstants.HEADER);
                        byteBuffer.putShort((short)2);
                        byteBuffer.putInt(port);
                        byteBuffer.put(sn);
                        int len = byteBuffer.position();
                        // 直接根据发送者构建一份回送信息
                        DatagramPacket responsePacket = new DatagramPacket(buffer, len, receivePack.getAddress(), responsePort);
                        ds.send(responsePacket);
                        System.out.println(String.format("ServerProvider response to:%s\tport:%d\tdataLen:%d", clientIp, responsePort, len));
                    }else{
                        System.out.println(String.format("ServerProvider receive cmd nonsupport; cmd:%d\tport:%d", cmd, port));
                    }
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }finally {
                close();
            }
            System.out.println("UDPProvider Finished.");
        }

        private void close(){
            if(null == ds) return;
            ds.close();
            ds = null;
        }

        /**
         * 提供结束
         */
        void exit(){
            done = true;
            close();
        }
    }
}
